using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;

namespace Xioa_UI.Controls;

public class XioaPassword : TextBox
{
    public XioaPassword()
    {
        //this.TextChanged += PasswordTextChanged;
        //this.SourceUpdated += XioaPassword_SourceUpdated;
    }

    private void XioaPassword_SourceUpdated(object? sender, System.Windows.Data.DataTransferEventArgs e)
    {
    }

    #region InputHint

    /// <summary>
    /// 获取或者设置水印
    /// </summary>
    public string InputHint
    {
        get { return (string)GetValue(InputHintProperty); }
        set { SetValue(InputHintProperty, value); }
    }

    public static readonly DependencyProperty InputHintProperty =
        DependencyProperty.Register("InputHint", typeof(string), typeof(XioaPassword));

    #endregion

    #region private fields

    private ToggleButton? PART_SeePassword;

    /// <summary>
    /// 该属性是为了防止明文转化为密文后，设置Text时，再次触发Text_Changed事件
    /// </summary>
    public bool mIsHandledTextChanged { get; set; } = true;

    private StringBuilder? mPasswordBuilder;

    #endregion

    private void PasswordTextChanged(object sender, TextChangedEventArgs e)
    {
        if (!this.mIsHandledTextChanged)
            return;
        //Password = Text;
        //if (Password != null && Password.Length > 0)
        //{
        //    Text = "";
        //    for (int i = 0; i < Password.Length - 1; i++)
        //    {
        //        Text += PasswordChar;
        //    }
        //}
        this.Focusable = false;
        foreach (TextChange c in e.Changes)
        {
            //从密码文中根据本次Change对象的索引和长度删除对应个数的字符
            this.Password = this.Password.Remove(c.Offset, c.RemovedLength);
            //将Text新增的部分记录给密码文
            this.Password = this.Password.Insert(c.Offset, Text.Substring(c.Offset, c.AddedLength));
        }


        if (!this.ShowPassword)
        {
            this.SetText(ConvertToPasswordChar(Text.Length));
        }

        this.Focusable = true;
        this.SelectionStart = this.Text.Length + 1;
    }

    #region IsCanSeePassword

    /// <summary>
    /// 获取或者设置是否能看见密码
    /// </summary>
    [Bindable(true), Description("获取或者设置是否能看见密码")]
    public bool IsCanSeePassword
    {
        get { return (bool)GetValue(IsCanSeePasswordProperty); }
        set { SetValue(IsCanSeePasswordProperty, value); }
    }

    public static readonly DependencyProperty IsCanSeePasswordProperty =
        DependencyProperty.Register("IsCanSeePassword", typeof(bool), typeof(XioaPassword),
            new PropertyMetadata(true, IsCanSeePasswordChangedCallback));

    private static void IsCanSeePasswordChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        XioaPassword passowrdBox = d as XioaPassword;
        if (passowrdBox != null && passowrdBox.PART_SeePassword != null)
        {
            passowrdBox.PART_SeePassword.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed;
        }
    }

    #endregion

    private void SetEvent()
    {
        this.TextChanged += ZPasswordBox_TextChanged;
        if (this.PART_SeePassword != null)
        {
            this.PART_SeePassword.Checked += (o, e) =>
            {
                this.SetText(this.Password);
                this.ShowPassword = true;
            };
            this.PART_SeePassword.Unchecked += (o, e) =>
            {
                this.SetText(this.ConvertToPasswordChar(this.Password.Length));
                this.ShowPassword = false;
            };
        }
    }

    private void ZPasswordBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (!this.mIsHandledTextChanged)
            return;

        foreach (TextChange c in e.Changes)
        {
            //从密码文中根据本次Change对象的索引和长度删除对应个数的字符
            this.Password = this.Password.Remove(c.Offset, c.RemovedLength);
            //将Text新增的部分记录给密码文
            this.Password = this.Password.Insert(c.Offset, Text.Substring(c.Offset, c.AddedLength));
        }

        if (!this.ShowPassword)
        {
            this.SetText(ConvertToPasswordChar(Text.Length));
        }

        //将光标放到最后面
        this.SelectionStart = this.Text.Length + 1;
    }

    #region Override

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        this.PART_SeePassword = this.GetTemplateChild("PART_SeePassword") as ToggleButton;
        if (this.PART_SeePassword != null)
        {
            this.PART_SeePassword.Visibility = this.IsCanSeePassword ? Visibility.Visible : Visibility.Collapsed;
        }

        this.SetEvent();

        //回显密码
        this.SetText(this.ConvertToPasswordChar(this.Password.Length));

        //密码框禁止复制
        this.CommandBindings.Add(new System.Windows.Input.CommandBinding(ApplicationCommands.Copy,
            CommandBinding_Executed, CommandBinding_CanExecute));
    }

    private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
    }

    private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.Handled = true;
    }

    //public override void OnCornerRadiusChanged(CornerRadius newValue)
    //{
    //    //根据密码框边框圆角自动设置图标背景框圆角
    //    this.IconCornerRadius = new CornerRadius(newValue.TopLeft, 0, 0, newValue.BottomLeft);
    //}

    #endregion

    private void SetText(string str)
    {
        this.mIsHandledTextChanged = false;
        this.Text = str;
        this.mIsHandledTextChanged = true;
    }

    private string ConvertToPasswordChar(int length)
    {
        if (mPasswordBuilder != null)
        {
            mPasswordBuilder.Clear();
        }
        else
        {
            mPasswordBuilder = new StringBuilder();
        }

        for (var i = 0; i < length; i++)
        {
            mPasswordBuilder.Append(this.PasswordChar);
        }

        return mPasswordBuilder.ToString();
    }

    public static readonly DependencyProperty PasswordCharProperty =
        ElementBase.Property<XioaPassword, char>("PasswordCharProperty", '*');

    public bool ShowPassword
    {
        get { return (bool)GetValue(ShowPasswordProperty); }
        private set { SetValue(ShowPasswordProperty, value); }
    }

    public static readonly DependencyProperty ShowPasswordProperty =
        DependencyProperty.Register("ShowPassword", typeof(bool), typeof(XioaPassword),
            new PropertyMetadata(false, ShowPasswordChanged));

    private static void ShowPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var passwordBox = d as XioaPassword;
        if (passwordBox != null)
        {
            passwordBox.SelectionStart = passwordBox.Text.Length + 1;
        }
    }

    public char PasswordChar
    {
        get => (char)GetValue(PasswordCharProperty);
        set => SetValue(PasswordCharProperty, value);
    }


    #region CornerRadius

    public CornerRadius CornerRadius
    {
        get { return (CornerRadius)GetValue(CornerRadiusProperty); }
        set { SetValue(CornerRadiusProperty, value); }
    }

    public static readonly DependencyProperty CornerRadiusProperty =
        DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(XioaPassword),
            new PropertyMetadata(CornerRadiusChanged));

    private static void CornerRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        XioaPassword textbox = d as XioaPassword;
        if (textbox != null && e.NewValue != null)
        {
            textbox.OnCornerRadiusChanged((CornerRadius)e.NewValue);
        }
    }

    public void OnCornerRadiusChanged(CornerRadius newValue)
    {
        //根据密码框边框圆角自动设置图标背景框圆角
        this.IconCornerRadius = new CornerRadius(newValue.TopLeft, 0, 0, newValue.BottomLeft);
    }

    #endregion

    #region IconCornerRadius

    /// <summary>
    /// 获取或者设置图标边框的圆角（可以不用手动设置，系统会根据密码框的圆角值自动设置该值）
    /// </summary>
    [Bindable(true), Description("获取或者设置图标边框的圆角（可以不用手动设置，系统会根据密码框的圆角值自动设置该值）")]
    public CornerRadius IconCornerRadius
    {
        get { return (CornerRadius)GetValue(IconCornerRadiusProperty); }
        set { SetValue(IconCornerRadiusProperty, value); }
    }

    public static readonly DependencyProperty IconCornerRadiusProperty =
        DependencyProperty.Register("IconCornerRadius", typeof(CornerRadius), typeof(XioaPassword));

    #endregion

    #region Password

    [Bindable(true), Description("获取或者设置当前密码值")]
    public string Password
    {
        get => (string)GetValue(PasswordProperty);
        set => SetValue(PasswordProperty, value);
    }

    public static readonly DependencyProperty PasswordProperty =
        DependencyProperty.Register("Password", typeof(string),
            typeof(XioaPassword),
            new PropertyMetadata(string.Empty));

    #endregion

    #region IconBackground

    /// <summary>
    /// 获取或者设置图标边框背景色
    /// </summary>
    [Bindable(true), Description("获取或者设置图标边框背景色")]
    public Brush IconBackground
    {
        get { return (Brush)GetValue(IconBackgroundProperty); }
        set { SetValue(IconBackgroundProperty, value); }
    }

    public static readonly DependencyProperty IconBackgroundProperty =
        DependencyProperty.Register("IconBackground", typeof(Brush), typeof(XioaPassword));

    #endregion

    #region IconWidth

    /// <summary>
    /// 获取或者设置图标的大小
    /// </summary>
    [Bindable(true), Description("获取或者设置图标的大小")]
    public double IconWidth
    {
        get { return (double)GetValue(IconWidthProperty); }
        set { SetValue(IconWidthProperty, value); }
    }

    public static readonly DependencyProperty IconWidthProperty =
        DependencyProperty.Register("IconWidth", typeof(double), typeof(XioaPassword));

    #endregion

    #region IconPadding

    /// <summary>
    /// 获取或者设置图标的内边距
    /// </summary>
    [Bindable(true), Description("获取或者设置图标的内边距")]
    public Thickness IconPadding
    {
        get { return (Thickness)GetValue(IconPaddingProperty); }
        set { SetValue(IconPaddingProperty, value); }
    }

    public static readonly DependencyProperty IconPaddingProperty =
        DependencyProperty.Register("IconPadding", typeof(Thickness), typeof(XioaPassword));

    #endregion

    #region IconBorderThickness

    /// <summary>
    /// 获取或者设置图标边框的粗细与大小
    /// </summary>
    public Thickness IconBorderThickness
    {
        get { return (Thickness)GetValue(IconBorderThicknessProperty); }
        set { SetValue(IconBorderThicknessProperty, value); }
    }

    public static readonly DependencyProperty IconBorderThicknessProperty =
        DependencyProperty.Register("IconBorderThickness", typeof(Thickness), typeof(XioaPassword));

    #endregion

    #region IconForeground

    /// <summary>
    /// 获取或者设置图标的颜色
    /// </summary>
    [Bindable(true), Description("获取或者设置图标的颜色")]
    public Brush IconForeground
    {
        get { return (Brush)GetValue(IconForegroundProperty); }
        set { SetValue(IconForegroundProperty, value); }
    }

    public static readonly DependencyProperty IconForegroundProperty =
        DependencyProperty.Register("IconForeground", typeof(Brush), typeof(XioaPassword));

    #endregion

    #region IconPathData

    /// <summary>
    /// 获取或者设置密码框图标
    /// </summary>
    [Bindable(true), Description("获取或者设置密码框图标")]
    public PathGeometry IconPathData
    {
        get => (PathGeometry)GetValue(IconPathDataProperty);
        set => SetValue(IconPathDataProperty, value);
    }

    public static readonly DependencyProperty IconPathDataProperty =
        DependencyProperty.Register("IconPathData",
            typeof(PathGeometry), typeof(XioaPassword));

    #endregion


    public static readonly DependencyProperty PlaceholderProperty =
        ElementBase.Property<XioaPassword, string>("PlaceholderProperty", "");

    public static readonly DependencyProperty PlaceholderFontSizeProperty =
        ElementBase.Property<XioaPassword, double>("PlaceholderFontSizeProperty", 10);

    public static readonly DependencyProperty TitleProperty =
        ElementBase.Property<XioaPassword, string>("TitleProperty", "");

    public static readonly DependencyProperty TitleMinWidthProperty =
        ElementBase.Property<XioaPassword, double>("TitleMinWidthProperty", 100);

    public static readonly DependencyProperty TitleForegroundProperty =
        ElementBase.Property<XioaPassword, Brush>("TitleForegroundProperty");

    public static readonly DependencyProperty TitleFontSizeProperty =
        ElementBase.Property<XioaPassword, double>("TitleFontSizeProperty", 10);

    public static readonly DependencyProperty ShowPlaceholderProperty =
        ElementBase.Property<XioaPassword, Visibility>("ShowPlaceholderProperty", Visibility.Visible);


    public Visibility ShowPlaceholder
    {
        get => (Visibility)GetValue(ShowPlaceholderProperty);
        set => SetValue(ShowPlaceholderProperty, value);
    }

    public double PlaceholderFontSize
    {
        get => (double)GetValue(PlaceholderFontSizeProperty);
        set => SetValue(PlaceholderFontSizeProperty, value);
    }

    public string Placeholder
    {
        get => (string)GetValue(PlaceholderProperty);
        set => SetValue(PlaceholderProperty, value);
    }

    public string Title
    {
        get => (string)GetValue(TitleProperty);
        set => SetValue(TitleProperty, value);
    }

    public double TitleMinWidth
    {
        get => (double)GetValue(TitleMinWidthProperty);
        set => SetValue(TitleMinWidthProperty, value);
    }

    public double TitleFontSize
    {
        get => (double)GetValue(TitleFontSizeProperty);
        set => SetValue(TitleFontSizeProperty, value);
    }

    public Brush TitleForeground
    {
        get => (Brush)GetValue(TitleForegroundProperty);
        set => SetValue(TitleForegroundProperty, value);
    }

    public static readonly DependencyProperty MouseMoveBackgroundProperty =
        ElementBase.Property<XioaPassword, Brush>("MouseMoveBackgroundProperty");

    public Brush MouseMoveBackground
    {
        get { return (Brush)GetValue(MouseMoveBackgroundProperty); }
        set { SetValue(MouseMoveBackgroundProperty, value); }
    }


    static XioaPassword()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(XioaPassword),
            new FrameworkPropertyMetadata(typeof(XioaPassword)));
    }
}